#include "mainwindow.h"
#include "urlaction.h"
#include "page.h"
#include <KAction>
#include <KActionCollection>
#include <KActionMenu>
#include <KMenu>
#include <KStandardAction>
#include <KStatusBar>
#include <ktabwidget.h>
#include <kcmultidialog.h>
#include <kauthorized.h>
#include <klocale.h>
#include <kurl.h>
#include <QGridLayout>
#include <QList>
#include <kparts/browserextension.h>
#include <KMessageBox>
#include <KDialog>
#include <QKeySequence>
#include <QProgressBar>
#include <kprocess.h>

#include <config.h>
#ifdef NEPOMUK_FOUND
    #include <nepomuk/tag.h>
    #include <nepomuk/kmetadatatagwidget.h>
    #include "tagdialog.h"
#endif

// EurekaWindow constructor: creates the main KTabWidget, sets up toolbar, etc.
EurekaWindow::EurekaWindow( QWidget *parent ) : KXmlGuiWindow( parent )
{
    // Set icon
    setWindowIcon( KIcon( "internet-web-browser" ) );
    // Setup menu and toolbar actions
    setupActions();

    // Setup tab of pages
    pages = new KTabWidget;
    connect( pages, SIGNAL( currentChanged( int ) ), this, SLOT( currentTabChanged( int ) ) );
    connect( pages, SIGNAL( closeRequest( QWidget* ) ), this, SLOT( closeTab( QWidget* ) ) );
    connect( pages, SIGNAL( mouseDoubleClick() ), m_newTabAct, SLOT( trigger() ) );
    setCentralWidget( pages );

    // Setup progress bar widget
    progressBar = new QProgressBar();
    progressBar->setMaximumSize( 100, 25 );
    statusBar()->addPermanentWidget( progressBar, -2 );

    // Finally, draw the interface
    setupGUI();
}

// EurekaWindow::setupActions: connects toolbar and menubar action signals to various slots.
void EurekaWindow::setupActions()
{
    // Standard KDE actions
    KStandardAction::quit( this, SLOT( close() ), actionCollection() );
    KStandardAction::back( this, SLOT( back() ), actionCollection() );
    KStandardAction::forward( this, SLOT( forward() ), actionCollection() );
    KStandardAction::preferences( this, SLOT( configure() ), actionCollection() );
    reloadAction = KStandardAction::redisplay( this, SLOT( reload() ), actionCollection() );
    reloadAction->setText( i18n( "Reload" ) );

    // 'New tab' button
    m_newTabAct = new UrlAction( "about:blank", actionCollection() );
    actionCollection()->addAction( "tab-new", m_newTabAct );
    m_newTabAct->setText( i18n( "New Tab" ) );
    m_newTabAct->setIcon( KIcon( "tab-new" ) );
    m_newTabAct->setShortcut( Qt::CTRL + Qt::Key_N );
    connect( m_newTabAct, SIGNAL( triggered( KUrl, KParts::OpenUrlArguments, KParts::BrowserArguments ) ), this, SLOT( open( const KUrl&, const KParts::OpenUrlArguments&, const KParts::BrowserArguments& ) ) );

    // 'Close tab' button
    KAction *closeTabAct = actionCollection()->addAction( "tab-close" );
    closeTabAct->setText( i18n( "Close tab" ) );
    closeTabAct->setIcon( KIcon( "tab-close" ) );
    closeTabAct->setShortcut( Qt::CTRL + Qt::Key_W );
    connect( closeTabAct, SIGNAL( triggered() ), this, SLOT( closeTab() ) );

    // Tags support
    #ifdef NEPOMUK_FOUND
    tagsMenu = new KActionMenu( i18n( "Tags" ), actionCollection() );
    actionCollection()->addAction( "tags", tagsMenu );
    connect( tagsMenu->menu(), SIGNAL( aboutToShow() ), this, SLOT( setupTagsMenu() ) );
    #endif

    // Location bar is a KLineEdit
    addressBarAction = new UrlAction( "about:blank", actionCollection() );
    actionCollection()->addAction( "addressBar", addressBarAction );
    addressBar = new KLineEdit();
    addressBarAction->setText( i18n( "Location" ) );
    addressBarAction->setDefaultWidget( addressBar );
    connect( addressBar, SIGNAL( returnPressed() ), addressBarAction, SLOT( trigger() ) );
    connect( addressBarAction, SIGNAL( triggered( KUrl, KParts::OpenUrlArguments, KParts::BrowserArguments ) ), this, SLOT( goTo( const KUrl&, const KParts::OpenUrlArguments&, const KParts::BrowserArguments& ) ) );
    connect( addressBar, SIGNAL( textChanged( const QString& ) ), addressBarAction, SLOT( setUrl( const QString& ) ) );

    // Go button
    KAction* goAction = actionCollection()->addAction( "go-jump-locationbar" );
    goAction->setText( i18n( "Go" ) );
    goAction->setIcon( KIcon( "go-jump-locationbar" ) );
    connect( goAction, SIGNAL( triggered() ), addressBarAction, SLOT( trigger() ) );

    // Stop button
    stopAction = actionCollection()->addAction( "process-stop" );
    stopAction->setText( i18n( "Stop" ) );
    stopAction->setIcon( KIcon( "process-stop" ) );
    stopAction->setShortcut( Qt::Key_Escape );
    connect( stopAction, SIGNAL( triggered() ), this, SLOT( stop() ) );
}

// EurekaWindow::open: opens a new tab with a KUrl.
void EurekaWindow::open( const KUrl& url, const KParts::OpenUrlArguments& arguments, const KParts::BrowserArguments& browserArguments )
{
    // Create all the needed objects.
    QWidget* tab = new QWidget(); // The QWidget for the tab.
    QGridLayout* layout = new QGridLayout(); // The QGridLayout.
    // The Page.
    Page* page = new Page( url, arguments, browserArguments, this );

    // Create the new tab and add to it.
    layout->addWidget( page );
    tab->setLayout( layout );
    int index = pages->addTab( tab, i18n( "Loading..." ) );
    pages->setCurrentIndex( index );
    if ( pages->count() > 1 ) pages->setCloseButtonEnabled( true );

    // Setup the UI.
    connect( page, SIGNAL( newTitle( const QString& ) ), this, SLOT( setCurrentTabText( const QString& ) ) );
    connect( page, SIGNAL( newTitle( const QString& ) ), this, SLOT( setCaption( const QString& ) ) );
    connect( page, SIGNAL( newLocation( const QString& ) ), addressBar, SLOT( setText( const QString& ) ) );
    connect( page, SIGNAL( newStatus( const QString& ) ), statusBar(), SLOT( showMessage( const QString& ) ) );
    connect( page, SIGNAL( newProgress( int ) ), progressBar, SLOT( setValue( int ) ) );
    connect( page, SIGNAL( newTab( const KUrl &, const KParts::OpenUrlArguments, KParts::BrowserArguments ) ), this, SLOT( open( const KUrl &, const KParts::OpenUrlArguments, KParts::BrowserArguments ) ) );
    connect( page, SIGNAL( newWindow( const KUrl & ) ), this, SLOT( newWindow( const KUrl & ) ) );
    connect( page, SIGNAL( loading( bool ) ), stopAction, SLOT( setEnabled( bool ) ) );
    connect( page, SIGNAL( loading( bool ) ), reloadAction, SLOT( setDisabled( bool ) ) );
}

// EurekaWindow::closeTab: closes the current tab
void EurekaWindow::closeTab( QWidget* page )
{
    if ( pages->isCloseButtonEnabled() ) {
        pages->removePage( page );
        if ( pages->count() <= 1 ) pages->setCloseButtonEnabled( false );
    }
}

// EurekaWindiw::currentTabChanged: update the UI after the user changes the tab
void EurekaWindow::currentTabChanged( int index )
{
    Page* page = pages->widget( index )->findChild<Page*>();
    addressBar->setText( page->url().url() );
    setCaption( page->title() );
}

// EurekaWindow::setupTagsMenu: setup the "tags" menu.
#ifdef NEPOMUK_FOUND
void EurekaWindow::setupTagsMenu()
{
    if ( ! tagsMenu->menu()->isEmpty() ) tagsMenu->menu()->clear();
    KAction* addAct = actionCollection()->addAction( "add-to-tag" );
    addAct->setText( i18n( "Tag this page" ) );
    addAct->setIcon( KIcon( "list-add" ) );
    tagsMenu->addAction( addAct );
    connect( addAct, SIGNAL( triggered() ), this, SLOT( tagPage() ) );
    QList<Nepomuk::Tag> tags = Nepomuk::Tag::allTags();
    for ( int i = 0; i < tags.count(); i++ ) {
        KActionMenu* tagAction = new KActionMenu( tags.value( i ).genericLabel(), actionCollection() );
        tagsMenu->addAction( tagAction );
        QList<Nepomuk::Resource> contents = tags.value( i ).tagOf();
        for ( int l = 0; l < contents.count(); l++ ) {
            UrlAction* newAction = new UrlAction( contents.value( l ).genericLabel(), actionCollection(), contents.value( l ).uri() );
            tagAction->addAction( newAction );
            connect( newAction, SIGNAL( triggered( const KUrl &, const KParts::OpenUrlArguments, KParts::BrowserArguments ) ), this, SLOT( goTo( const KUrl &, const KParts::OpenUrlArguments, KParts::BrowserArguments ) ) );
        }
    }
}

void EurekaWindow::tagPage()
{
    Page* page = pages->currentWidget()->findChild<Page*>();
    KUrl url = page->url();
    QString title = page->title();
    TagDialog* td = new TagDialog( url, title, this );
    td->show();
}
#endif

void EurekaWindow::configure()
{
    KCMultiDialog* configureDialog = new KCMultiDialog(  this );
#define ADD_MODULE( name )    if ( KAuthorized::authorizeControlModule( name ) )\
                                configureDialog->addModule( name );
    ADD_MODULE( "khtml_filter" )
    ADD_MODULE( "khtml_fonts" )
    ADD_MODULE( "khtml_java_js" )
    ADD_MODULE( "khtml_plugins" )
    ADD_MODULE( "cookies" )
    ADD_MODULE( "crypto" )
    ADD_MODULE( "useragent" )
    ADD_MODULE( "filetypes" )
    ADD_MODULE( "cache" )
    ADD_MODULE( "proxy" )
    ADD_MODULE( "kcmcss" )
#undef ADD_MODULE
    configureDialog->show();
}

// Warn before closing if the user has multiple tabs.
bool EurekaWindow::queryClose()
{
    if ( pages->count() <= 1 ) return true;
    switch (KMessageBox::questionYesNo( this,
        i18n( "You have multiple tabs open in this window,"
              "are you sure you want to quit?" ) ) ) {
    case KMessageBox::Yes :
        return true;
    default:
        return false;
    }
}

